package com.ruicar.afs.cloud.basic.proceeds.debit.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.basic.proceeds.debit.service.BasicDebitPayBatchService;
import com.ruicar.afs.cloud.basic.proceeds.pay.entity.BasicAutoPaymentConfig;
import com.ruicar.afs.cloud.basic.proceeds.pay.entity.BasicPaymentBank;
import com.ruicar.afs.cloud.basic.proceeds.pay.entity.BasicPaymentPool;
import com.ruicar.afs.cloud.basic.proceeds.pay.service.BasicAutoPaymentConfigService;
import com.ruicar.afs.cloud.basic.proceeds.pay.service.BasicPaymentBankService;
import com.ruicar.afs.cloud.basic.proceeds.pay.service.BasicPaymentPoolService;
import com.ruicar.afs.cloud.common.modules.contract.enums.PaymentStatusEnum;
import com.ruicar.afs.cloud.common.modules.contract.enums.YesOrNoEnum;
import com.ruicar.afs.cloud.common.util.EmptyUtils;
import com.ruicar.afs.cloud.components.datadicsync.DicHelper;
import com.ruicar.afs.cloud.components.datadicsync.dto.DicDataDto;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
@AllArgsConstructor
public class BasicDebitPayBatchServiceImpl implements BasicDebitPayBatchService {

	private final BasicPaymentPoolService paymentPoolService;
	private final BasicPaymentBankService basicPaymentBankService;
	private final BasicAutoPaymentConfigService basicAutoPaymentConfigService;


	public void autoPay(Map<Long, List<BasicPaymentPool>> poolMap, BasicAutoPaymentConfig autoPaymentConfig) {
		/**  付款通道 by ZC.GUO  **/
		Map<String, List<DicDataDto>> dicMap = DicHelper.getDicMaps("mappingBank");
		List<DicDataDto> list = dicMap.get("mappingBank");
		Map<String,String> mappingBankMap = new HashMap<>(list.size());
		if (EmptyUtils.isNotEmpty(list)){
			list.forEach(dto->{
				mappingBankMap.put(dto.getValue(),dto.getTitle());
			});
		}
		Map<Long,List<List<BasicPaymentPool>>> finalMap = this.splitList(poolMap,autoPaymentConfig.getBatchMaxNum());
		for (Map.Entry<Long, List<List<BasicPaymentPool>>> map : finalMap.entrySet()) {
			BasicPaymentBank bankAccount = basicPaymentBankService.getById(map.getKey());
			/**  付款通道 by ZC.GUO  **/
			String chlCd = mappingBankMap.get(bankAccount.getPaymentBankCode());
			/**  有付款通道才发 by ZC.GUO  **/
			if (EmptyUtils.isNotEmpty(chlCd)) {
				List<List<BasicPaymentPool>> sendList = map.getValue();
				for (List<BasicPaymentPool> poolList : sendList){
					List<Long> idList = poolList.stream().map(BasicPaymentPool::getId).collect(Collectors.toList());
					/**  整批锁定 by ZC.GUO  **/
					if (EmptyUtils.isNotEmpty(idList) && paymentPoolService.readyBatchWhenStartPay(idList)){
						try{
							paymentPoolService.autoPay(poolList,chlCd,bankAccount);
						}catch (Exception e){
							log.error(e.getMessage());
						}finally{
							/**  整批解锁 by ZC.GUO  **/
							paymentPoolService.updatePaymentPoolStatus(YesOrNoEnum.no,idList);
						}
					}
				}
			}
		}
	}

	@Override
	public void autoPay() {
		BasicAutoPaymentConfig autoPaymentConfig = null;
		List<BasicAutoPaymentConfig> autoPaymentConfigList = basicAutoPaymentConfigService.list();
		if (EmptyUtils.isNotEmpty(autoPaymentConfigList)){
			autoPaymentConfig = autoPaymentConfigList.get(0);
			autoPaymentConfig.setWorkStartDate(DateUtil.parse(DateUtil.format(Calendar.getInstance().getTime(),"yyyy-MM-dd")+" "+autoPaymentConfig.getWorkStartTime(),"yyyy-MM-dd HH:mm:ss"));
			autoPaymentConfig.setWorkEndDate(DateUtil.parse(DateUtil.format(Calendar.getInstance().getTime(),"yyyy-MM-dd")+" "+autoPaymentConfig.getWorkEndTime(),"yyyy-MM-dd HH:mm:ss"));
			if (YesOrNoEnum.yes.equals(autoPaymentConfig.getEnableAutoPay())){
				Date now = Calendar.getInstance().getTime();
				if (now.after(autoPaymentConfig.getWorkStartDate())&&now.before(autoPaymentConfig.getWorkEndDate())){
					/**  待付款数据 by ZC.GUO  **/
					List<BasicPaymentPool> poolList = paymentPoolService.list(Wrappers.<BasicPaymentPool>query().lambda()
							.eq(BasicPaymentPool::getIsPayment,YesOrNoEnum.yes)
							.ne(BasicPaymentPool::getIsPaying,YesOrNoEnum.yes)
							.in(BasicPaymentPool::getPaymentStatus, PaymentStatusEnum.waitPayment, PaymentStatusEnum.failPayment));
					/**  付款数据筛选并结构化 by ZC.GUO  **/
					if (EmptyUtils.isNotEmpty(poolList)){
						Map<Long,List<BasicPaymentPool>> poolMap = this.structPaymentList(autoPaymentConfig,poolList);
						/**  批量付款 by ZC.GUO  **/
						this.autoPay(poolMap,autoPaymentConfig);
						log.info("自动付款任务执行完成");
					}
				}else{
					log.info("当前不在自动付款时间，本次自动付款任务执行结束");
				}
			}else {
				log.info("自动付款开关已关闭，本次自动付款任务执行结束");
			}
		}else{
			log.info("未找到自动付款配置，本次自动付款任务执行结束");
		}
	}

	private Map<Long,List<BasicPaymentPool>> structPaymentList(BasicAutoPaymentConfig autoPaymentConfig,List<BasicPaymentPool> poolList){
		Map<Long,List<BasicPaymentPool>> finalPoolMap = new HashMap<>(16);

		Map<String,List<BasicPaymentPool>> poolMap = poolList.stream()
				.collect(Collectors.groupingBy(BasicPaymentPool::getReceiptBankCode));
		poolMap.entrySet().forEach(map ->{
			/**  对应的付款账号 by ZC.GUO  **/
			BasicPaymentBank bankAccount = basicAutoPaymentConfigService.takePayAccount(map.getKey());
			if (EmptyUtils.isNotEmpty(bankAccount)){
				/**  付款银行不是暂不自动付款银行 by ZC.GUO  **/
				if (EmptyUtils.isEmpty(autoPaymentConfig.getNoAutoBank())
						|| (EmptyUtils.isNotEmpty(autoPaymentConfig.getNoAutoBank()) && !autoPaymentConfig.getNoAutoBank().contains(bankAccount.getPaymentBankCode()))) {
					if (EmptyUtils.isNotEmpty(finalPoolMap.get(bankAccount.getId()))){
						List<BasicPaymentPool> sendPoolList = finalPoolMap.get(bankAccount.getId());
						sendPoolList.addAll(map.getValue());
						finalPoolMap.put(bankAccount.getId(),sendPoolList);
					}else{
						finalPoolMap.put(bankAccount.getId(),map.getValue());
					}
				}
			}
		});
		return finalPoolMap;
	}

	private Map<Long,List<List<BasicPaymentPool>>> splitList(Map<Long, List<BasicPaymentPool>> poolMap, int len){
		Map<Long,List<List<BasicPaymentPool>>> finalMap = new HashMap<>(poolMap.size());
		if (EmptyUtils.isNotEmpty(poolMap)){
			for (Map.Entry<Long, List<BasicPaymentPool>> map : poolMap.entrySet()) {
				List<BasicPaymentPool> poolList = map.getValue();
				List<List<BasicPaymentPool>> resultList = new ArrayList<>();
				int size = poolList.size();
				int count = (size + len - 1) / len;
				for (int i = 0; i < count; i++) {
					List<BasicPaymentPool> subList = poolList.subList(i * len, ((i + 1) * len > size ? size : len * (i + 1)));
					resultList.add(subList);
				}
				finalMap.put(map.getKey(),resultList);
			}
		}
		return finalMap;
	}

}
